package com.scalar.forecast.adaptor.ikanos;

import com.scalar.ScalarException;
import com.scalar.chiptrack.adaptor.AdaptorUtils;
import com.scalar.chiptrack.adaptor.dao.AdaptorRunInfo;
import com.scalar.chiptrack.adaptor.ikanos.forecast.ForecastAdaptor;
import com.scalar.chiptrack.adaptor.utils.Parser;
import com.scalar.chiptrack.adaptor.utils.ParserFactory;
import com.scalar.chiptrack.adaptor.utils.ParserResult;
import com.scalar.chiptrack.adaptor.utils.XLSParserImpl;
import com.scalar.chiptrack.commons.Constants;
import com.scalar.chiptrack.commons.Labels;
import com.scalar.chiptrack.db.DataSource;
import com.scalar.chiptrack.jobs.JobHandler;
import com.scalar.chiptrack.users.notification.dao.NotificationDAO;
import com.scalar.chiptrack.utils.ConfigManager;
import com.scalar.chiptrack.utils.Logger;
import com.scalar.chiptrack.utils.Mailer;
import com.scalar.chiptrack.utils.StringUtils;
import com.scalar.forecast.salesForecastEntry.RowData;
import com.scalar.forecast.salesForecastEntry.SlotData;
import org.apache.struts.util.MessageResources;

import java.io.File;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

/**
 * Forecast parser for Ikanos new forecast sheet which has lot of additional data along with the forecast.
 */
public class NewForecastParser extends JobHandler {
	private Logger m_parserLogger = null;
	private String m_dataSourceDir = null;

	public NewForecastParser() throws Exception {
		try {
			m_dataSourceDir = ConfigManager.getForcastPortingFileDir();

			if (m_dataSourceDir != null) {
				AdaptorUtils.makeAllAdaptorDirs(m_dataSourceDir);

				m_parserLogger = AdaptorUtils.getDataParserLogger(m_dataSourceDir, "SalesForecast");
				AdaptorUtils.setLogger(m_parserLogger);
			}
		}
		catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static void main(String[] agrs) throws Exception {
		NewForecastParser parser = new NewForecastParser();
		parser.execute();
	}

	// To be implemented by sub classes
	public void execute() throws Exception {
		boolean success = false;
		AdaptorUtils.printHeader("SALES FORECAST PORTING", CONSTANT_PARSER);

		ArrayList successFileList = new ArrayList();
		File doneDestDir = new File(m_dataSourceDir + "/done");
		File dataoutDir = new File(m_dataSourceDir);

		File[] fileList = dataoutDir.listFiles();

		if ((fileList == null) || (fileList.length <= 3)) {
			log("No file found in directory: " + dataoutDir);
			throw new ScalarException("\n+-----------No file found in directory " + dataoutDir + "-----\n\n");
		}

		for (int p = 0; p < fileList.length; p++) {
			if (fileList[p].isDirectory() || !fileList[p].getName().contains("Sales_Forecast")) {
				continue;
			}
			log("Parsing Sale Forecast File:" + fileList[p].getName());
			ArrayList<RowData> salesForecastList = new ArrayList<RowData>();
			try {
				//TO PARSE THE SALES FORECAST SHEET
				salesForecastList = parseForecastFile(fileList[p]);
				success = true;
			}
			catch (Exception e) {
				success = false;
				e.printStackTrace();
			}

			String portingStatusMsg = null;

			if (success) //SEND PORTING STATUS MAIL
			{
				log("Porting Sales Forecast Details completed successfully....");
				log("Sending porting status mail...");
				portingStatusMsg = preparePortingStatusMsg(salesForecastList);
				if (portingStatusMsg == null || portingStatusMsg.equals("")) {
					log("WARNING!! WARNING!! Porting Status Message is Empty, not sending mail");
				} else {
					try {
						StringBuffer msg = new StringBuffer();
						msg.append("<HTML><HEAD><TITLE>Sales Forecast Porting Status</TITLE></HEAD>");
						msg.append("<BODY ALIGN='CENTER'><TABLE STYLE='FONT-SIZE: 8PT; COLOR: BLACK; FONT-FAMILY: VERDANA' BORDERCOLOR='#FFFFFF' CELLSPACING='1' CELLPADDING='3' BORDER=0 ALIGN='CENTER'>");
						msg.append("<TR BGCOLOR='#CCCCFF'><TD COLSPAN='8' ALIGN='CENTER'><B>SALES FORECAST PORTING STATUS REPORT</B></TD></TR>");
						msg.append("<TR BGCOLOR='#D3D3D6' ALIGN='CENTER'>");
						msg.append("<TD><B>S.No</B></TD>");
						msg.append("<TD><B>Customer Name</B></TD>");
						msg.append("<TD><B>").append(MessageResources.getMessageResources(Labels.APPLICATION_RESOURCE_PROPERTIES).getMessage("label.sales.endCustomer")).append("</B></TD>");
						msg.append("<TD><B>").append(MessageResources.getMessageResources(Labels.APPLICATION_RESOURCE_PROPERTIES).getMessage("label.sales.endUser")).append("</B></TD>");
						msg.append("<TD><B>").append("Carrier").append("</B></TD>");
						msg.append("<TD><B>").append(MessageResources.getMessageResources(Labels.APPLICATION_RESOURCE_PROPERTIES).getMessage("label.mktgPartNumber")).append("</B></TD>");
						msg.append("<TD><B>").append("Is Ported").append("</B></TD>");
						msg.append("<TD><B>REMARKS</B></TD>");
						msg.append("</TR>");
						msg.append(portingStatusMsg);
						msg.append("</TABLE></BODY></HTML>");
						String fromEmail = ConfigManager.getScalarAdminEmail();
						sendSalesForecastPortingAlert("Sales Forecast porting status alert", msg.toString(), fromEmail, Constants.SALES_ORDER_PORTING_NOTIFICATION);
						log("Porting status mail sent successfully");
					}
					catch (ScalarException e) {
						log("**WARNING** Could not send Porting Status alert mail:", e);
					}
				}
			}

			successFileList.add(fileList[p]);

			int adaptor_id = AdaptorRunInfo.getLastRunAdaptorId(ForecastAdaptor.ADAPTOR_NAME, CONSTANT_ADAPTOR);

			if (success) {
				AdaptorRunInfo.saveAdaptorLastUpdatedStatus(CONSTANT_PARSER, ForecastAdaptor.ADAPTOR_NAME, CONSTANT_SUCCESS, adaptor_id);
				log("SUCCESSFULLY UPDATED IN THE DATABASE");

				//Move the files to Done directory
				AdaptorUtils.moveFilesToDone(successFileList, doneDestDir);
			}
		}
	}

	private ArrayList<RowData> parseForecastFile(File shipFile) throws Exception {
		if (shipFile == null) throw new ScalarException("Filename argument is null");

		ParserResult result = null;
		Connection conn = null;
		PreparedStatement pstmt = null;
		CallableStatement cstmt = null;
		boolean success = false;
		ArrayList<RowData> forecastList = new ArrayList<RowData>();
		final String transactionId = System.currentTimeMillis() + "";
		final String htmlNewLine = "<br>";
		try {
			log("\nFound " + shipFile.getName());
			log("\nParsing the file for Sales Forecast Report ...");
			Parser parser = ParserFactory.getXLSParser(shipFile);

			((XLSParserImpl) parser).setHeaderRowIdx(3);
			((XLSParserImpl) parser).setDataStartRowIdx(4);

			result = parser.parse();
			log("Moving forecast data to history tables");
			moveDataToHistoryTables();
			log("Successfully Moved forecast data to history tables");

			while (result.next()) {
				StringBuilder remarks = new StringBuilder();
				RowData rowData = new RowData();
				try {
					rowData.setCustomerName(result.getString("Customer Name"));
					rowData.setEndUserName(result.getString("OEM"));
					rowData.setEndCustomerName(result.getString("ODM"));
					rowData.setCarrier(result.getString("Carrier"));
					rowData.setProductName(result.getString("Marketing Part Number"));
					rowData.setPorted(true);

					forecastList.add(rowData);

					conn = DataSource.getConnection();
					//1. SAVE BASIC PROJECT DETAILS
					log("**SAVING PROJECT DETAILS FOR ROWIDX:" + result.getFileRowIdx());
					int paramNo = 1;
					cstmt = conn.prepareCall(" { CALL SP_SAVE_PROJECT_DETAILS (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) }");
					cstmt.setString(paramNo++, result.getString("Customer Name"));
					cstmt.setString(paramNo++, result.getString("ODM"));
					cstmt.setString(paramNo++, result.getString("OEM"));
					cstmt.setString(paramNo++, result.getString("Carrier"));
					cstmt.setString(paramNo++, result.getString("Status"));
					cstmt.setString(paramNo++, result.getString("Sales Person"));
					cstmt.setString(paramNo++, result.getString("Marketing Part Number"));
					cstmt.setString(paramNo++, result.getString("Chipset Part Name"));
					cstmt.registerOutParameter(paramNo++, java.sql.Types.INTEGER);
					cstmt.registerOutParameter(paramNo++, java.sql.Types.INTEGER);
					try {
						cstmt.executeUpdate();
					} catch (SQLException e) {
						log("**ERROR** unable to save project details", e);
						rowData.setPorted(false);
						remarks.append("Project save failed: ").append(e.getMessage());
						throw e;
					}
					int projId = cstmt.getInt(9);
					int prodId = cstmt.getInt(10);
					log("**PROJID:" + projId + " PRODID:" + prodId + " FOR ROWIDX:" + result.getFileRowIdx());
					if (projId > 0 && prodId > 0) {
						//2. SAVE PROJ PROD ADDITIONAL DATA
						log("**SAVING PROJ PROD ADDITIONAL DATA FOR ROWIDX:" + result.getFileRowIdx());
						paramNo = 1;
						cstmt.close();
						cstmt = null;
						cstmt = conn.prepareCall(" { CALL SP_SAVE_PROJECT_PRODUCT_ADDITIONAL_DETAILS (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) }");
						cstmt.setInt(paramNo++, projId);
						cstmt.setInt(paramNo++, prodId);
						cstmt.setString(paramNo++, result.getString("Book"));
						cstmt.setString(paramNo++, result.getString("BU"));
						cstmt.setString(paramNo++, result.getString("PLM"));
						cstmt.setString(paramNo++, result.getString("Product Segment"));
						cstmt.setString(paramNo++, result.getString("Product Family"));
						cstmt.setString(paramNo++, result.getString("Chipset"));
						cstmt.setString(paramNo++, result.getString("Region"));
						cstmt.setString(paramNo++, result.getString("Carrier"));
						cstmt.setString(paramNo++, result.getString("Chipset Part Name"));
						cstmt.setString(paramNo++, result.getString("Chipset Description"));
						cstmt.setString(paramNo++, result.getString("Chip Type"));
						cstmt.setString(paramNo++, result.getString("Component Description"));
						cstmt.setString(paramNo++, result.getString("Port Count"));
						cstmt.setString(paramNo++, result.getString("chipset  component count"));
						cstmt.setString(paramNo++, result.getString("package size"));
						cstmt.setString(paramNo++, result.getString("Package Type"));
						cstmt.setString(paramNo++, result.getString("Packing Type"));
						cstmt.setString(paramNo++, result.getString("Packing Quantity*"));
						cstmt.setString(paramNo++, result.getString("Samples"));
						cstmt.setString(paramNo++, transactionId);

						try {
							cstmt.executeUpdate();
						} catch (SQLException e) {
							log("**ERROR** unable to save project product details", e);
							rowData.setPorted(false);
							remarks.append(htmlNewLine);
							remarks.append("Project Product details save failed: ").append(e.getMessage());
						}

						//3. SAVE FORECAST DETAILS
						List headings = result.getHeadings();
						List<SlotData> fcSlotDataList = new ArrayList<SlotData>();
						List<SlotData> additionalDataSlotDataList = new ArrayList<SlotData>();
						SlotData slotData = null;
						if (headings != null) {
							for (Object headingObj : headings) {
								String headingName = String.class.cast(headingObj);
								if (headingName.toLowerCase().endsWith("port volume")) {
									int qtr = getQtrFromHeading(headingName);
									int year = getYearFromHeading(headingName);
									slotData = getSlotDataFromList(additionalDataSlotDataList, qtr, year);
									try {
										slotData.setPortVolume(result.getDouble(headingName));
									} catch (NumberFormatException e) {
										log("**ERROR** Invalid Port Volume for column:" + headingName, e);
										rowData.setPorted(false);
										remarks.append(htmlNewLine);
										remarks.append(headingName + ": Invalid Port Volume: ").append(e.getMessage());
									}
								} else if (headingName.toLowerCase().endsWith("volume")) {
									int qtr = getQtrFromHeading(headingName);
									int year = getYearFromHeading(headingName);
									slotData = getSlotDataFromList(fcSlotDataList, qtr, year);
									try {
										slotData.setQty(result.getInt(headingName));
									} catch (NumberFormatException e) {
										log("**ERROR** Invalid Qty for column:" + headingName, e);
										rowData.setPorted(false);
										remarks.append(htmlNewLine);
										remarks.append(headingName + ": Invalid Qty: ").append(e.getMessage());
									}
								} else if (headingName.toLowerCase().endsWith("asp")) {
									int qtr = getQtrFromHeading(headingName);
									int year = getYearFromHeading(headingName);
									slotData = getSlotDataFromList(fcSlotDataList, qtr, year);
									try {
										slotData.setPrice(result.getDouble(headingName));
									} catch (NumberFormatException e) {
										log("**ERROR** Invalid Price for column:" + headingName, e);
										rowData.setPorted(false);
										remarks.append(htmlNewLine);
										remarks.append(headingName + ": Invalid Price: ").append(e.getMessage());
									}
								} else if (headingName.toLowerCase().endsWith("rebates")) {
									int qtr = getQtrFromHeading(headingName);
									int year = getYearFromHeading(headingName);
									slotData = getSlotDataFromList(additionalDataSlotDataList, qtr, year);
									try {
										slotData.setRebate(result.getDouble(headingName));
									} catch (NumberFormatException e) {
										log("**ERROR** Invalid Rebate for column:" + headingName, e);
										rowData.setPorted(false);
										remarks.append(htmlNewLine);
										remarks.append(headingName + ": Invalid Rebate: ").append(e.getMessage());
									}
								} else if (headingName.toLowerCase().endsWith("material costs")) {
									int qtr = getQtrFromHeading(headingName);
									int year = getYearFromHeading(headingName);
									slotData = getSlotDataFromList(additionalDataSlotDataList, qtr, year);
									try {
										slotData.setMaterialCost(result.getDouble(headingName));
									} catch (NumberFormatException e) {
										log("**ERROR** Invalid material cost for column:" + headingName, e);
										rowData.setPorted(false);
										remarks.append(htmlNewLine);
										remarks.append(headingName + ": Invalid Material Cost: ").append(e.getMessage());
									}
								} else if (headingName.toLowerCase().endsWith("royalty")) {
									int qtr = getQtrFromHeading(headingName);
									int year = getYearFromHeading(headingName);
									slotData = getSlotDataFromList(additionalDataSlotDataList, qtr, year);
									try {
										slotData.setRoyalty(result.getDouble(headingName));
									} catch (NumberFormatException e) {
										log("**ERROR** Invalid Royalty for column:" + headingName, e);
										rowData.setPorted(false);
										remarks.append(htmlNewLine);
										remarks.append(headingName + ": Invalid Royalty: ").append(e.getMessage());
									}
								}
							}
						}

						//SAVE FORECAST DATA LIST
						log("**SAVING FORECAST DETAILS FOR ROWIDX:" + result.getFileRowIdx());
						cstmt.close();
						cstmt = null;

						cstmt = conn.prepareCall(" { CALL SP_SAVE_FORECAST_DATA (?, ?, ?, ?, ?, ?, ?, ? ) }");
						for (SlotData fcSlotData : fcSlotDataList) {
							paramNo = 1;
							cstmt.setInt(paramNo++, projId);
							cstmt.setInt(paramNo++, prodId);
							cstmt.setInt(paramNo++, fcSlotData.getYear());
							cstmt.setInt(paramNo++, fcSlotData.getQtr());
							cstmt.setInt(paramNo++, fcSlotData.getQty());
							cstmt.setDouble(paramNo++, fcSlotData.getPrice());
							cstmt.setString(paramNo++, "SYSTEM");
							cstmt.setString(paramNo++, transactionId);

							cstmt.addBatch();
						}
						try {
							cstmt.executeBatch();
						} catch (SQLException e) {
							log("**ERROR** Could not save forecast data", e);
							rowData.setPorted(false);
							remarks.append(htmlNewLine);
							remarks.append("Could not save forecast data: ").append(e.getMessage());
						}

						//SAVE FORECAST ADDITIONAL DATA
						log("**SAVING FORECAST ADDITIONAL DATA FOR ROWIDX:" + result.getFileRowIdx());
						cstmt.close();
						cstmt = null;

						cstmt = conn.prepareCall(" { CALL SP_SAVE_FORECAST_ADDITONAL_DATA (?, ?, ?, ?, ?, ?, ?, ?, ? ) }");

						for (SlotData additionalDataSlotData : additionalDataSlotDataList) {
							paramNo = 1;
							cstmt.setInt(paramNo++, projId);
							cstmt.setInt(paramNo++, prodId);
							cstmt.setInt(paramNo++, additionalDataSlotData.getYear());
							cstmt.setInt(paramNo++, additionalDataSlotData.getQtr());
							cstmt.setDouble(paramNo++, additionalDataSlotData.getRebate());
							cstmt.setDouble(paramNo++, additionalDataSlotData.getMaterialCost());
							cstmt.setDouble(paramNo++, additionalDataSlotData.getRoyalty());
							cstmt.setDouble(paramNo++, additionalDataSlotData.getPortVolume());
							cstmt.setString(paramNo++, transactionId);


							cstmt.addBatch();
						}
						try {
							cstmt.executeBatch();
						} catch (SQLException e) {
							log("**ERROR** Could not save forecast additional data", e);
							rowData.setPorted(false);
							remarks.append(htmlNewLine);
							remarks.append("Could not save forecast additional data: ").append(e.getMessage());
						}

					} else {
						//product not found
						log("***PRODUCT NOT FOUND*** MKTG PART NUMBER: " + result.getString("Marketing Part Number") + " for ROWIDX: " + result.getFileRowIdx());
						rowData.setPorted(false);
						remarks.append(htmlNewLine);
						remarks.append("<B>Product</B> not found in the system");
					}
					if (conn != null) {
						log("**COMMITTING ROWIDX: " + result.getFileRowIdx());
						conn.commit();
						success = true;
					}
				} catch (Exception ex) {
					success = false;
					log("ERROR!!!ERROR!!! While Porting the Forecast data for RowIdx:" + result.getFileRowIdx(), ex);
				}
				finally {
					rowData.setRemarks(remarks.toString());
					if (!success && conn != null) {
						try {
							conn.rollback();
						} catch (SQLException ignore) {
						}
					}
					if (cstmt != null) {
						try {
							cstmt.close();
						} catch (SQLException ignore) {
						}
					}
					if (conn != null) {
						try {
							conn.close();
						} catch (SQLException ignore) {
						}
					}
				}
			}
		}
		catch (Exception ex) {
			ex.printStackTrace();
			throw ex;
		}

		return forecastList;

	}// end of prase Forecast Report method


	private String preparePortingStatusMsg(ArrayList<RowData> rowDataList) {
		final int SUCCESS = 0;
		final int SALES_PARTNUMBER_NOT_FOUND = 1;
		final int CUSTOMER_CREATED = 2;

		RowData rowData = null;
		StringBuffer statusMsg = new StringBuffer();
		int rowDataListSize = (rowDataList == null) ? 0 : rowDataList.size();
		int count = 0;
		for (int i = 0; i < rowDataListSize; i++) {
			rowData = rowDataList.get(i);
			if (!rowData.isPorted()) {
				statusMsg.append("<TR BGCOLOR='#E6E6E6' ALIGN='CENTER'>");
				statusMsg.append("<TD ALIGN='LEFT'>").append(++count).append("</TD>");
				statusMsg.append("<TD ALIGN='LEFT'>").append((rowData.getCustomerName() == null) ? "" : rowData.getCustomerName()).append("</TD>");
				statusMsg.append("<TD ALIGN='LEFT'>").append((rowData.getEndCustomerName() == null) ? "" : rowData.getEndCustomerName()).append("</TD>");
				statusMsg.append("<TD ALIGN='LEFT'>").append((rowData.getEndUserName() == null) ? "" : rowData.getEndUserName()).append("</TD>");
				statusMsg.append("<TD ALIGN='LEFT'>").append((rowData.getCarrier() == null) ? "" : rowData.getCarrier()).append("</TD>");
				statusMsg.append("<TD ALIGN='LEFT'>").append((rowData.getProductName() == null) ? "" : rowData.getProductName()).append("</TD>");
				statusMsg.append("<TD ALIGN='LEFT'>").append(rowData.isPorted()).append("</TD>");
				statusMsg.append("<TD ALIGN='LEFT'>").append(rowData.getRemarks()).append("</TD>");
				statusMsg.append("</TR>");
			}
		}
		if (count == 0) {
			//All ported successfully
			statusMsg.append("<TR BGCOLOR='#E6E6E6' ALIGN='CENTER'>");
			statusMsg.append("<TD ALIGN='LEFT'>").append("<B>All ported successfully</B>").append("</TD>");
			statusMsg.append("</TR>");
		}
		return statusMsg.toString();
	}

	private void sendSalesForecastPortingAlert(String subject, String message, String fromEmail, String notificationType) throws Exception {
		ArrayList emailList = NotificationDAO.loadEmailsByNotificationType(null, notificationType);
		String[] emails = new String[emailList.size()];
		emailList.toArray(emails);
		String toEmails = StringUtils.concatStrings(emails, Mailer.EMAIL_SEPARATOR);
		log("Sending sales forecast porting alerts to: " + toEmails);
		try {
			Mailer.send(fromEmail, toEmails, null, null, subject, message, null, Mailer.CONTENT_TYPE_HTML, false);
		}
		catch (Exception e) {
			throw new ScalarException("Could not send email notifications", e);
		}
	}

	private void log(String message) {
		log(message, null);
	}

	private void log(String message, Throwable e) {
		if (m_parserLogger != null) {
			m_parserLogger.logDebug(message + LINE_SEPARATOR, e);
		}
		System.out.println(message);
		if (e != null) {
			e.printStackTrace();
		}
	}

	private SlotData getSlotDataFromList(List<SlotData> slotDataList, int qtr, int year) {
		SlotData slotData = null;
		for (SlotData tmp : slotDataList) {
			if (tmp.getQtr() == qtr && tmp.getYear() == year) {
				slotData = tmp;
				break;
			}
		}
		if (slotData == null) { //notfound, need to add..
			slotData = new SlotData();
			slotData.setQtr(qtr);
			slotData.setYear(year);
			slotDataList.add(slotData);
		}
		return slotData;
	}

	private int getQtrFromHeading(String headingName) throws ScalarException {
		if (headingName.toUpperCase().startsWith("Q1"))
			return 1;
		else if (headingName.toUpperCase().startsWith("Q2"))
			return 2;
		else if (headingName.toUpperCase().startsWith("Q3"))
			return 3;
		else if (headingName.toUpperCase().startsWith("Q4"))
			return 4;

		throw new ScalarException("Qtr no not found in headingName:" + headingName);
	}

	private int getYearFromHeading(String headingName) throws NumberFormatException {
		return 2000 + Integer.parseInt(headingName.substring(2, 4));
	}

	private void moveDataToHistoryTables() throws Exception {
		Connection conn = null;
		PreparedStatement pstmt = null;
		boolean success = false;
		try {

			conn = DataSource.getConnection();

			pstmt = conn.prepareStatement("INSERT INTO FCENTRYHISTORY SELECT * FROM FCENTRYMASTER");
			pstmt.executeUpdate();
			pstmt.close();
			pstmt = null;

			pstmt = conn.prepareStatement("DELETE FROM FCENTRYMASTER");
			pstmt.executeUpdate();
			pstmt.close();
			pstmt = null;

			pstmt = conn.prepareStatement("INSERT INTO FCENTRYMASTER_ADDITIONAL_DATA_HISTORY_TABLE SELECT * FROM FCENTRYMASTER_ADDITIONAL_DATA_TABLE");
			pstmt.executeUpdate();
			pstmt.close();
			pstmt = null;

			pstmt = conn.prepareStatement("DELETE FROM FCENTRYMASTER_ADDITIONAL_DATA_TABLE");
			pstmt.executeUpdate();

			pstmt.close();
			pstmt = null;

			conn.commit();
			success = true;
		} catch (Exception e) {
			log("Could not move to data History tables", e);
			throw e;
		} finally {
			if (!success && conn != null) {
				try {
					conn.rollback();
				} catch (SQLException ignore) {
				}
			}
			if (pstmt != null) {
				try {
					pstmt.close();
				} catch (SQLException ignore) {
				}
			}
			if (conn != null) {
				try {
					conn.close();
				} catch (SQLException ignore) {
				}
			}
		}
	}
}